package com.ruoyi.framework.typeHandler;

import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;

/**
 * mybatis String类型敏感字段处理类
 * 可以通过实现TypeHandler，但是BaseTypeHandler已经实现了，我们可以继承它
 */
public class SensitiveColumnHandler extends BaseTypeHandler<String> {

//    private static final String key = "4v6hbv5683reu88o";

    /**
     * 16字节
     */
    private static final String ENCODE_KEY = "6309BhpOd925h48z";
    private static final String IV_KEY = "5J22S4jmSrE0339u";

    /**
     * 设置参数值，在此处对字段值进行加密处理
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        // 如果字段或字段值为空，不进行处理
        if(StringUtils.isEmpty(parameter)){
            ps.setString(i, parameter);
            return;
        }
        // 对字段值进行加密，此处使用hutool工具，有其他使用其他即可
//        AES aes = SecureUtil.aes(key.getBytes(StandardCharsets.UTF_8));
//        String secretStr = aes.encryptHex(parameter);
        String secretStr = encryptFromString(parameter, Mode.CBC, Padding.ZeroPadding);

        ps.setString(i, secretStr);
    }

    /**
     * 获取值内容
     */
    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        if(Objects.isNull(value)){
            return null;
        }
        // 对字段值进行加密，此处使用hutool工具，有其他使用其他即可
//        AES aes = SecureUtil.aes(key.getBytes(StandardCharsets.UTF_8));
//        return aes.decryptStr(value);
        return decryptFromString(value, Mode.CBC, Padding.ZeroPadding);
    }

    /**
     * 获取值内容
     */
    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String value = rs.getString(columnIndex);
        if(Objects.isNull(value)){
            return null;
        }
        // 对字段值就行加密，此处使用hutool工具，有其他使用其他即可
//        AES aes = SecureUtil.aes(key.getBytes(StandardCharsets.UTF_8));
//        return aes.decryptStr(value);
        return decryptFromString(value, Mode.CBC, Padding.ZeroPadding);
    }

    /**
     * 获取值内容
     */
    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        if(Objects.isNull(value)){
            return null;
        }
        // 对字段值进行加密，此处使用hutool工具，有其他使用其他即可
//        AES aes = SecureUtil.aes(key.getBytes(StandardCharsets.UTF_8));
//        return aes.decryptStr(value);
        return decryptFromString(value, Mode.CBC, Padding.ZeroPadding);
    }


    public static String encryptFromString(String data, Mode mode, Padding padding) {
        AES aes;
        if (Mode.CBC == mode) {
            aes = new AES(mode, padding,
                    new SecretKeySpec(ENCODE_KEY.getBytes(), "AES"),
                    new IvParameterSpec(IV_KEY.getBytes()));
        } else {
            aes = new AES(mode, padding,
                    new SecretKeySpec(ENCODE_KEY.getBytes(), "AES"));
        }
        return aes.encryptBase64(data, StandardCharsets.UTF_8);
    }

    public static String decryptFromString(String data, Mode mode, Padding padding) {
        AES aes;
        if (Mode.CBC == mode) {
            aes = new AES(mode, padding,
                    new SecretKeySpec(ENCODE_KEY.getBytes(), "AES"),
                    new IvParameterSpec(IV_KEY.getBytes()));
        } else {
            aes = new AES(mode, padding,
                    new SecretKeySpec(ENCODE_KEY.getBytes(), "AES"));
        }
        byte[] decryptDataBase64 = aes.decrypt(data);
        return new String(decryptDataBase64, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) {
        String encryptData = encryptFromString("aaa123456..", Mode.CBC, Padding.ZeroPadding);
        System.out.println("加密：" + encryptData);
        String decryptData = decryptFromString(encryptData, Mode.CBC, Padding.ZeroPadding);
        System.out.println("解密：" + decryptData);
    }
}
